/**
 * 热力图图层类
 * 封装热力图渲染逻辑，支持数据动态更新、热力参数调节等
 */

import { Map as OlMap } from 'ol';
import { Heatmap as OlHeatmapLayer } from 'ol/layer';
import { Vector as VectorSource } from 'ol/source';
import { Feature } from 'ol';
import { Point, Geometry } from 'ol/geom';
import { BaseLayer } from './BaseLayer';
import { HeatmapLayerOptions, FeatureData, Coordinate } from '../types';
import { DataUtil } from '../utils/data';

/**
 * 热力图图层类
 */
export class HeatmapLayer extends BaseLayer {
  /** 图层配置 */
  protected options: HeatmapLayerOptions;
  /** 矢量数据源 */
  private source: VectorSource<Feature<Point>> | null = null;

  /**
   * 构造函数
   * @param options 图层配置
   */
  constructor(options: HeatmapLayerOptions = {}) {
    super(options);
    this.options = {
      radius: 20,
      blur: 15,
      gradient: ['#00f', '#0ff', '#0f0', '#ff0', '#f00'],
      adaptiveRadius: true,
      ...options
    };
  }

  /**
   * 创建图层
   */
  protected createLayer(): void {
    // 创建矢量数据源
    this.source = new VectorSource<Feature<Point>>();

    // 创建热力图图层
    this.layer = new OlHeatmapLayer({
      source: this.source,
      radius: this.options.radius || 20,
      blur: this.options.blur || 15,
      gradient: this.options.gradient || ['#00f', '#0ff', '#0f0', '#ff0', '#f00'],
      weight: (feature: Feature<Geometry>) => {
        // 获取权重值
        if (this.options.weightField) {
          const weight = feature.get(this.options.weightField);
          return typeof weight === 'number' ? weight : 1;
        }
        return 1;
      }
    });

    // 如果启用自适应半径，监听地图缩放事件
    if (this.options.adaptiveRadius && this.map) {
      this.map.getView().on('change:resolution', () => {
        this.updateAdaptiveRadius();
      });
    }
  }

  /**
   * 更新自适应半径
   */
  private updateAdaptiveRadius(): void {
    if (!this.map || !this.layer || !this.options.adaptiveRadius) {
      return;
    }

    const zoom = this.map.getView().getZoom() || 10;
    // 根据缩放级别调整半径（缩放级别越大，半径越小）
    const baseRadius = this.options.radius || 20;
    const adaptiveRadius = Math.max(5, baseRadius * (1 / Math.pow(1.5, zoom - 10)));

    (this.layer as OlHeatmapLayer).setRadius(adaptiveRadius);
  }

  /**
   * 添加要素
   * @param data 要素数据
   */
  addFeature(data: FeatureData): void {
    if (!this.source) {
      throw new Error('Layer not initialized');
    }

    const feature = DataUtil.createPointFeature(data.geometry as Coordinate, data.properties);
    if (data.id !== undefined) {
      feature.setId(data.id);
    }
    this.source.addFeature(feature);
    this.emit('featureadd', feature);
  }

  /**
   * 批量添加要素
   * @param dataList 要素数据数组
   */
  addFeatures(dataList: FeatureData[]): void {
    if (!this.source) {
      throw new Error('Layer not initialized');
    }

    const features = dataList.map(data => {
      const feature = DataUtil.createPointFeature(data.geometry as Coordinate, data.properties);
      if (data.id !== undefined) {
        feature.setId(data.id);
      }
      return feature;
    });

    this.source.addFeatures(features);
    this.emit('featuresadd', features);
  }

  /**
   * 移除要素
   * @param featureId 要素ID
   */
  removeFeature(featureId: string | number): void {
    if (!this.source) return;

    const feature = this.source.getFeatureById(featureId);
    if (feature && feature instanceof Feature) {
      this.source.removeFeature(feature);
      this.emit('featureremove', feature);
    }
  }

  /**
   * 清空所有要素
   */
  clearFeatures(): void {
    if (this.source) {
      this.source.clear();
      this.emit('featuresclear');
    }
  }

  /**
   * 更新数据
   * @param dataList 要素数据数组
   */
  updateData(dataList: FeatureData[]): void {
    this.clearFeatures();
    this.addFeatures(dataList);
  }

  /**
   * 设置热力半径
   * @param radius 半径（像素）
   */
  setRadius(radius: number): void {
    this.options.radius = radius;
    if (this.layer && !this.options.adaptiveRadius) {
      (this.layer as OlHeatmapLayer).setRadius(radius);
    } else if (this.options.adaptiveRadius) {
      this.updateAdaptiveRadius();
    }
  }

  /**
   * 获取热力半径
   * @returns 半径
   */
  getRadius(): number {
    return this.options.radius || 20;
  }

  /**
   * 设置模糊度
   * @param blur 模糊度
   */
  setBlur(blur: number): void {
    this.options.blur = blur;
    if (this.layer) {
      (this.layer as OlHeatmapLayer).setBlur(blur);
    }
  }

  /**
   * 获取模糊度
   * @returns 模糊度
   */
  getBlur(): number {
    return this.options.blur || 15;
  }

  /**
   * 设置颜色梯度
   * @param gradient 颜色数组
   */
  setGradient(gradient: string[]): void {
    this.options.gradient = gradient;
    if (this.layer) {
      (this.layer as OlHeatmapLayer).setGradient(gradient);
    }
  }

  /**
   * 获取颜色梯度
   * @returns 颜色数组
   */
  getGradient(): string[] {
    return this.options.gradient || ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];
  }

  /**
   * 设置权重字段
   * @param fieldName 字段名
   */
  setWeightField(fieldName: string): void {
    this.options.weightField = fieldName;
    // 需要重新创建图层以应用新的权重函数
    if (this.map && this.layer) {
      const oldSource = this.source;
      this.map.removeLayer(this.layer);
      this.createLayer();
      if (oldSource) {
        this.source?.addFeatures(oldSource.getFeatures());
      }
      this.map.addLayer(this.layer);
    }
  }

  /**
   * 设置是否自适应半径
   * @param adaptive 是否自适应
   */
  setAdaptiveRadius(adaptive: boolean): void {
    this.options.adaptiveRadius = adaptive;
    if (adaptive) {
      this.updateAdaptiveRadius();
      if (this.map) {
        this.map.getView().on('change:resolution', () => {
          this.updateAdaptiveRadius();
        });
      }
    }
  }

  /**
   * 获取所有要素
   * @returns 要素数组
   */
  getFeatures(): Feature<Point>[] {
    return this.source?.getFeatures() || [];
  }
}

